home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / BSPTREE.ZIP / BSPTREE.TXT
Encoding:
Internet Message Format  |  1996-04-26  |  11.8 KB

  1. Date: Mon, 28 Nov 94 17:30:41 GMT
  2.  
  3.  
  4.  
  5. BSP Trees
  6.  
  7. ---------
  8.  
  9.  
  10. This article explains how BSP (binary space partitioning) trees can be used in 
  11.  
  12. a game such as DOOM as part of the rendering pipeline to perform back-face
  13.  
  14. culling, partial Z-ordering and hidden surface removal.
  15.  
  16.  
  17. To explain the use of BSP trees, it is best to start with an example. Consider
  18.  
  19. a very simple DOOM level.
  20.  
  21.  
  22.      A---------------------------------a----------------------------------B
  23.  
  24.   |  |                                                                    |  |
  25.  
  26.   |  |                                            y                       |  |
  27.  
  28.   d1 |                                                                    |  b1
  29.  
  30.   |  |                               f'                                   |  |
  31.  
  32.   |  |                                                                    |  |
  33.  
  34.      |          C--------------------f-----------------------D            | 
  35.  
  36.   |  |          |                                            |            |  |
  37.  
  38.   |  |          |                    f"                      |            |  |
  39.  
  40.   |  d          |                                            |            b  |
  41.  
  42.   |  |          |                                            |            |  |
  43.  
  44.   |  |       e" e  e'                                     g' g  g"        |  |
  45.  
  46.   d2 |          |                                            |            |  b2
  47.  
  48.   |  |          |                                            |            |  |
  49.  
  50.   |  |          |                                            |            |  |
  51.  
  52.   |  |          E                                            F            |  |
  53.  
  54.   |  |                              x                                     |  |
  55.  
  56.   |  |                                                                    |  |
  57.  
  58.      G---------------------------------c----------------------------------H
  59.  
  60.                                                               
  61.  
  62.       ----c1---- ----------------------c2-------------------- -----c3-----    
  63.  
  64.  
  65.  
  66.  
  67. The level consists of a room within a room. The player cannot go outside of the
  68.  
  69. area within the square ABHG.
  70.  
  71.  
  72. First some definitions (sorry :-)
  73.  
  74.  
  75. The _vertices_ are marked A-H, the _faces_ are marked a-g.
  76.  
  77.  
  78. We define a _line_ by using an ordered pair of vertices, so that
  79.  
  80.  
  81.       a = (A,B)  e = (E,C)  f = (C,D)  g = (F,D)
  82.  
  83.  
  84. We say a point is to the _left_ of a line if it is to the left of the vector
  85.  
  86. between its two vertices, taken in order.
  87.  
  88.  
  89. So, in the above example, nothing is to the left of line a; everything is to
  90.  
  91. the right of it. Note that this depends upon our defintion of line a, and if
  92.  
  93. we had defined a = (B,A) then everything would be to the left of line a.
  94.  
  95.  
  96. A _face_ is a side of a line which is visible to the player. Wall e above, for
  97.  
  98. example, has two faces (marked e' and e"). Not all walls have two faces - if 
  99.  
  100. the player can never see one side of a wall it only has one.
  101.  
  102.  
  103. A face is fully defined by an ordered pair of vertices and an ordered pair of
  104.  
  105. faces - a left face and a right face.
  106.  
  107.  
  108. The BSP tree for the example above might look like this:
  109.  
  110.  
  111.  
  112.                      f 
  113.  
  114.                     / \
  115.  
  116.                    /   \ 
  117.  
  118.                   /     \
  119.  
  120.            a,d1,b1       e
  121.  
  122.                         / \
  123.  
  124.                        /   \
  125.  
  126.                       /     \
  127.  
  128.                  d2,c1       g
  129.  
  130.                             / \
  131.  
  132.                            /   \
  133.  
  134.                           /     \
  135.  
  136.                         c2       c3,b2
  137.  
  138.  
  139.  
  140. Each node contains a line. Everything to the left of that line is in the left
  141.  
  142. subtree, and everything to the right of that line is in the right subtree.
  143.  
  144.  
  145. Note that face d is neither completely to the right of nor to the left of face
  146.  
  147. f. To accomodate this, we split it up into two halves, and put one half into
  148.  
  149. the left subtree and one half into the right subtree. Thus, we have to generate
  150.  
  151. new faces in order to build the BSP tree.
  152.  
  153.  
  154. I will explain how the BSP tree is created later. Firstly, I will give the
  155.  
  156. algorithm used to render a picture using the tree.
  157.  
  158.  
  159. Suppose the player is standing at position 'x', and looking North.
  160.  
  161.  
  162. We start at the top of the tree at line f. We are standing to the right of line
  163.  
  164. f, so we go down the LEFT of the tree. This is because we want the furthest
  165.  
  166. polygons first.
  167.  
  168.  
  169. We come to the left-hand-most terminating node. We write down the faces here
  170.  
  171. in our notepad. "a,d1,b1".
  172.  
  173.  
  174. Since we've come to a terminator, we back up a level. Back to the top, but we
  175.  
  176. have to go down the right subtree yet. Firstly, though, we look at face f - the
  177.  
  178. deciding face for this node. We've got everything behind it in our list, we've
  179.  
  180. yet to look at anything in front of it, but we must put it into our list.
  181.  
  182. Note that face f has two sides - f' and f". Since we already know we're on the
  183.  
  184. right of line f, we know that we can only see its right side - so we write 
  185.  
  186. f" in our notepad. It now says a,d1,b1,f".
  187.  
  188.  
  189. Note, though, that if we were looking south (i.e. our line-of-sight vector
  190.  
  191. points away from face f) then we could not see either face f or anything on
  192.  
  193. the other side of face f - in this case, we just don't bother going any further
  194.  
  195. down the tree.
  196.  
  197.  
  198. Now we go down the subtree and come to node e. We are on the right of e, so we
  199.  
  200. go down the left subtree and get a terminal node - we just write d2,c1 in our
  201.  
  202. notepad. 
  203.  
  204.  
  205. Back up, decide on which side of e to put in. We decide e'. The notepad now 
  206.  
  207. says a,d1,b1,f",d2,c1,e'.
  208.  
  209.  
  210. Down the right subtree to node g. We're on the left, so down the right subtree
  211.  
  212. to c3,b2, up, check g (we're on the left = g'), back down to the final node,
  213.  
  214. get c2, up, up, up, and we're done.
  215.  
  216.  
  217. The notepad ends up saying:
  218.  
  219.  
  220. a d1 b1 f" d2 c1 e' c3 b2 g' c2
  221.  
  222.  
  223. If we draw these walls, in this order, then we will get the correct scene. I
  224.  
  225. would recommend using a one-dimensional Z-buffer to get finer granularity than
  226.  
  227. the painter's algorithm provides, before plotting the walls. Note also that
  228.  
  229. some walls are behind you - however, since you need to calculate their z
  230.  
  231. coordinates for the perspective transform, you can merely discard faces with
  232.  
  233. negative z values.
  234.  
  235.  
  236. Creating the BSP tree
  237.  
  238. ---------------------
  239.  
  240.  
  241. The BSP tree almost creates itself. The only difficulty is knowing when to stop
  242.  
  243. recursing. Notice that the terminal nodes are just put into the list - so a
  244.  
  245. sufficient condition for a group of faces to form a terminal node is that they
  246.  
  247. can be drawn in a set order without any mistakes occuring in the drawing. That
  248.  
  249. is, if wherever the player can stand, the group of walls will never obscure
  250.  
  251. each other. 
  252.  
  253.  
  254. So let us begin: Choose face f (the choice is fairly arbitrary - it is best
  255.  
  256. to choose faces which don't split many other faces up. However, in this case
  257.  
  258. it is unavoidable). Split up faces d and b, because they straddle the line f.
  259.  
  260. (The line you are splitting along is known as the _nodeline_ in DOOM-speak).
  261.  
  262.  
  263. Then put everything to the left of f in the left subtree, and vice-versa:
  264.  
  265.  
  266.  
  267.                             f
  268.  
  269.                            / \
  270.  
  271.                           /   \
  272.  
  273.                          /     \
  274.  
  275.                   a,d1,b1       b2,c,d2,e,g
  276.  
  277.  
  278. We can terminate the left node - because walls a,d1 and b1 form a convex
  279.  
  280. shape, they can never overlap each other from any point of view. However, on
  281.  
  282. the other side, face e can obscure face d2 from certain viewpoints (our example
  283.  
  284. viewpoint above, for one) so we divide along side e. This causes side c to be
  285.  
  286. split, but side a is not split because it's not in our current list of sides.
  287.  
  288.  
  289. The next level is:
  290.  
  291.  
  292.                             f
  293.  
  294.                            / \
  295.  
  296.                           /   \
  297.  
  298.                          /     \
  299.  
  300.                   a,d1,b1       e
  301.  
  302.                                / \
  303.  
  304.                               /   \ 
  305.  
  306.                              /     \
  307.  
  308.                         d2,c1       b2,c2,g
  309.  
  310.  
  311. Now, c1 and d2 never overlap, so we have another terminal node. We next divide
  312.  
  313. along line g, splitting c2 into c2 and c3, and the last nodes are terminals
  314.  
  315. (a node with one face in is always terminal :-).
  316.  
  317.  
  318. This is the basic idea behind a BSP tree - to give an example how effective it
  319.  
  320. is, consider standing at point y and looking North. Because you're looking
  321.  
  322. away from face f, you don't bother recursing down the entire left subtree. This
  323.  
  324. then very quickly gives you the ordered list of faces: a,d1,b1. 
  325.  
  326.  
  327. Refinements
  328.  
  329. -----------
  330.  
  331.  
  332. If at each node we define a bounding box for each subtree, such that every line
  333.  
  334. in a subtree is contained by its corresponding bounding box, then we can cut
  335.  
  336. some invisible polygons (ones which lie to the left or right of the screen) out
  337.  
  338. by comparing each bounding box with the cone of vision - if they don't
  339.  
  340. intersect, then you don't go down the whole subtree. DOOM does this, allowing
  341.  
  342. it to store an *entire* level in one huge BSP tree.
  343.  
  344.  
  345. Here's some pseudo-code to traverse the tree. The function left() returns TRUE
  346.  
  347. if the second input vector is to the left of the first input vector. This is
  348.  
  349. a simple dot product, and by pre-calculating the slope of the nodeline can be
  350.  
  351. done with one multiply and one subtract. 
  352.  
  353.  
  354. vector  player                         ; player's map position
  355.  
  356. vector  left_sightline                 ; vector representing a ray cast through
  357.  
  358.                                        ; the left-most pixel of the screen
  359.  
  360. vector  right_sightline                ; the right-most pixel of the screen
  361.  
  362.  
  363. structure node 
  364.  
  365. {
  366.  
  367.   vector vertex1
  368.  
  369.   vector vertex2
  370.  
  371.   node   left_subtree
  372.  
  373.   node   right_subtree
  374.  
  375.   face   left_face
  376.  
  377.   face   right_face
  378.  
  379.   box    bounding_box
  380.  
  381.   bool   terminal_node
  382.  
  383.   face   terminal_node_faces[lots]
  384.  
  385.  
  386.  
  387. recurse(node input)
  388.  
  389.  
  390. if (cone defined by left and right sightlines does not intersect the node's
  391.  
  392.     bounding box)
  393.  
  394.   return
  395.  
  396. fi
  397.  
  398.  
  399. if node.terminal_node
  400.  
  401.   ; terminal node - add faces to list
  402.  
  403.   add(node.terminal_node_faces)
  404.  
  405.   return
  406.  
  407. fi
  408.  
  409.  
  410. if left(vertex2-vertex1,player-vertex1)
  411.  
  412.   ; player is to the left of the nodeline
  413.  
  414.   if not left(vertex2-vertex1,right_sightline)
  415.  
  416.     ; sight points right - we are looking at the face
  417.  
  418.     recurse(node.right_subtree)
  419.  
  420.     add(node.left_face)
  421.  
  422.   fi
  423.  
  424.   ; now go down the left subtree
  425.  
  426.   recurse(node.left_subtree)
  427.  
  428. else
  429.  
  430.   ; player is to the right of the nodeline
  431.  
  432.   if left(vertex2-vertex1,left_sightline)
  433.  
  434.     ; sight points left - we are looking at the face
  435.  
  436.     recurse(node.left_subtree)
  437.  
  438.     add(node.right_face)
  439.  
  440.   fi
  441.  
  442.   ; now go down the right subtree
  443.  
  444.   recurse(node.right_subtree)
  445.  
  446. fi
  447.  
  448.  
  449. return                                                                         
  450.  
  451.  
  452. end recurse
  453.  
  454.  
  455. This isn't anywhere near a decent implementation - the data structures, for
  456.  
  457. example, leave a *lot* to be desired :-)
  458.  
  459.  
  460. It should be possible to encode all the functions inline; in fact, it would be
  461.  
  462. feasible to take a BSP tree and hard-code it into some run-time generated code
  463.  
  464. which you just call to recurse the tree ... but I'm just a hacker at heart ;-)
  465.  
  466.  
  467. Anyway, I hope this helps answer some peoples' questions on this subject. If
  468.  
  469. you have any more questions, please don't hesitate to email me.
  470.  
  471.  
  472. Catch you later,
  473.  
  474.  
  475. Eddie xxx
  476.  
  477.  
  478. ee@datcon.co.uk
  479.  
  480.  
  481.  
  482. ===========================================================================
  483.  
  484. Official Archimedes convertor of : Hear and remember, see and understand,
  485.  
  486. Wolfenstein 3D and proud of it!! : do and forget.
  487.  
  488. =================================: Something like that, anyway.
  489.  
  490.          ee@datcon.co.uk         ==========================================
  491.  
  492.  
  493.  
  494.